package cn.blnp.net.flowable.boot.localize.dynamic.temp;

import cn.blnp.net.flowable.boot.service.InjectUserTaskInProcessInstanceService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;

/**
 * <h3>流程动态增加临时节点</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/6/19 14:53
 */
@Slf4j
@SpringBootTest
public class DynamicAddTempNodeTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private IdentityService identityService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    @Resource
    private InjectUserTaskInProcessInstanceService injectUserTaskInProcessInstanceService;

    /**
     *  <h2>流程实例动态增加临时节点</h2>
     *  <ul>
     *      <li><b>【原】流程定义文件：</b>{@link flow/injectUserTaskProcess.bpmn20.xml}</li>
     *      <li>
     *          <b>【原】流程预览图：</b></br>
     *          <img src="https://cdn4.winhlb.com/2025/06/19/6853c54f14ea6.png" >
     *      </li>
     *      <li>
     *          <b>【动态】流程预览图：</b></br>
     *          <img src="https://cdn4.winhlb.com/2025/06/19/6853ce70191f1.png" >
     *      </li>
     *  </ul>
     **/
    @Test
    public void test() {
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/injectUserTaskProcess.bpmn20.xml")
                .name("动态新增临时节点案例")
                .deploy();
        log.info("部署ID：{}", deploy.getId());
        //流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义ID：{}", processDefinition.getId());
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(processDefinition.getId());
        log.info("流程实例ID：{}", procInst.getId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());

        //查询第一个任务
        Task firstTask = taskQuery.singleResult();
        //完成第一个任务
        taskService.complete(firstTask.getId());
        //查询第二个任务
        Task secondTask = taskQuery.singleResult();
        log.info("当前流程的流程定义id为：{}", procInst.getProcessDefinitionId());
        //查询流程模型
        BpmnModel bpmnModel = repositoryService
                .getBpmnModel(procInst.getProcessDefinitionId());
        log.info("当前流程的用户任务数为：{}", bpmnModel.getMainProcess()
                .findFlowElementsOfType(UserTask.class).size());

        //进行动态临时节点的新增
        injectUserTaskInProcessInstanceService.executeInjectUserTaskInProcessInstance(
                secondTask.getId(), "userTask4", "部门经理审批", "妲己");

        //重新查询流程实例
        procInst = runtimeService.createProcessInstanceQuery()
                .processInstanceId(procInst.getId()).singleResult();
        log.info("加节点后流程的流程定义id为：{}", procInst.getProcessDefinitionId());
        bpmnModel = repositoryService.getBpmnModel(procInst.getProcessDefinitionId());
        log.info("加节点后流程的用户任务数为：{}", bpmnModel.getMainProcess()
                .findFlowElementsOfType(UserTask.class).size());

        //依次办理流程中的各个任务
        while (true) {
            List<Task> tasks = taskQuery.list();
            if (CollectionUtils.isEmpty(tasks)) {
                break;
            }
            for (Task task : tasks) {
                log.info("办理用户任务：{}，节点key为：{}", task.getName(),
                        task.getTaskDefinitionKey());
                taskService.complete(task.getId());
            }
        }
        //查询历史流程实例
        HistoricProcessInstance hisProcInst = historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceId(procInst.getId()).singleResult();
        if (hisProcInst.getEndTime() != null) {
            log.info("流程已结束");
        }

        /**
         *  演示结果：
         *  2025-06-19 16:42:12.618  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 部署ID：247501
         * 2025-06-19 16:42:12.624  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 流程定义ID：injectUserTaskProcess:1:247503
         * 2025-06-19 16:42:12.699  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 流程实例ID：247504
         * 2025-06-19 16:42:12.755  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 当前流程的流程定义id为：injectUserTaskProcess:1:247503
         * 2025-06-19 16:42:12.756  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 当前流程的用户任务数为：3
         * 2025-06-19 16:42:13.333  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 加节点后流程的流程定义id为：247518
         * 2025-06-19 16:42:13.335  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 加节点后流程的用户任务数为：4
         * 2025-06-19 16:42:13.339  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 办理用户任务：财务经理审批，节点key为：userTask2
         * 2025-06-19 16:42:13.382  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 办理用户任务：部门经理审批，节点key为：userTask4
         * 2025-06-19 16:42:13.411  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 办理用户任务：总经理审批，节点key为：userTask3
         * 2025-06-19 16:42:13.473  INFO 53140 --- [           main] c.b.n.f.b.l.d.t.DynamicAddTempNodeTest   : 流程已结束
         **/
    }
}
